package cn.melonlib.aap.user.comp.service;

import cn.hutool.core.codec.Base64;
import cn.melonlib.aap.user.model.entity.*;
import cn.melonlib.aap.user.model.enums.AccountType;
import cn.melonlib.aap.user.model.enums.AuthMethod;
import cn.melonlib.aap.user.model.enums.LoginClient;
import cn.melonlib.aap.user.model.view.ProfileView;
import cn.melonlib.cores.aop.comp.web.WebInfo;
import cn.melonlib.cores.commons.comp.service.impl.WorkerBasicService;
import cn.melonlib.cores.jpa.model.bean.impl.DefaultQuery;
import cn.melonlib.cores.model.anno.*;
import cn.melonlib.cores.model.enums.QueryMode;
import cn.melonlib.security.encryption.anno.Encrypt;
import cn.melonlib.security.encryption.anno.SecurityService;
import cn.melonlib.security.encryption.comp.enc.EncryptionService;
import cn.melonlib.security.encryption.enums.EncTarget;
import com.fasterxml.jackson.core.type.TypeReference;
import org.intellij.lang.annotations.Language;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import javax.transaction.Transactional;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;

import static cn.melonlib.cores.commons.comp.service.impl.WorkerBasicService.ROOT_METHOD.*;
@Service
@WorkerComment("用户认证")
@WorkerService(
        module = "auth"
        ,model = @WorkerModel(
                name = "AuthAccount"
                ,modelType = Account.class
                ,voType = ProfileView.class
)
        ,ignores = {SAVE,REMOVE_BY_ID,REMOVE_BY_ID_LIST,SEARCH,LIST,TOTAL_COUNT,GET_BY_ID,LOAD_ALL}
)
@SecurityService
public class AccountPasswordAuthService extends WorkerBasicService<Account> {

    @Resource
    private EncryptionService encryptionService;

    @Resource
    private WebInfo webInfo;

    @WorkerQuery(mode = QueryMode.ONCE)
    @Transactional(value = Transactional.TxType.REQUIRED,rollbackOn = Exception.class)
    @WorkerComment("登陆验证")
    public ProfileView login(
            @WorkerParameter(value = "tenant",comment = "学校/机构",required = true) String tenant,
            @WorkerParameter(value = "account",comment = "登陆账号",required = true) String account,
            @WorkerParameter(value = "password",comment = "认证密码",required = true) String password)
            throws Exception{
        @Language("HQL") String hql="from cn.melonlib.aap.user.model.entity.Account where tenantId=?1 and account=?2";
        List<Account> accounts=this.dao.<List<Account>,DefaultQuery>search(new DefaultQuery(hql, List.of(tenant,account))).getResult();
        Assert.notEmpty(accounts,"未找到用户");
        @Language("HQL") String validPasswords="from AccountPassword where account=?1";
        List<AccountPassword> passwords=this.dao.<List<AccountPassword>,DefaultQuery>search(new DefaultQuery(validPasswords, List.of(accounts.get(0)))).getResult();
        Assert.notEmpty(passwords,"用户名或密码错误");
        String pwd=new String(encryptionService.storeDec(Base64.decode(passwords.get(0).getPassword())).getVal(), StandardCharsets.UTF_8);
        Assert.isTrue(Objects.equals(password,pwd),"用户名或密码错误");
        this.loginRecord(accounts.get(0));
        String token=accounts.get(0).getAccount()+"@"+accounts.get(0).getTenant();
        List<String> accountTypes=getJsonMapper().readValue(accounts.get(0).getAccountTypes(), new TypeReference<List<String>>() {
        });
        if(accountTypes.contains(AccountType.ADMIN.name())){
            @Language("HQL") String adminHql="from Administrator where code=?1";
            Administrator administrator=dao.<List<Administrator>,DefaultQuery>search(new DefaultQuery(adminHql,List.of(accounts.get(0).getAccount()))).getResult().get(0);
            return new ProfileView(accounts.get(0),administrator.getName(), Base64.encodeUrlSafe(encryptionService.transEnc(token.getBytes(StandardCharsets.UTF_8))));
        }else if(accountTypes.contains(AccountType.ORGANIZATION.name())){
            @Language("HQL") String schoolHql="from School where code=?1";
            School school=dao.<List<School>,DefaultQuery>search(new DefaultQuery(schoolHql,List.of(accounts.get(0).getAccount()))).getResult().get(0);
            return new ProfileView(accounts.get(0),school.getName(), Base64.encodeUrlSafe(encryptionService.transEnc(token.getBytes(StandardCharsets.UTF_8))));
        }else{
            @Language("HQL") String userHql="from User where code=?1";
            User user=dao.<List<User>,DefaultQuery>search(new DefaultQuery(userHql,List.of(accounts.get(0).getAccount()))).getResult().get(0);
            return new ProfileView(accounts.get(0),user.getNickName(), Base64.encodeUrlSafe(encryptionService.transEnc(token.getBytes(StandardCharsets.UTF_8))));
        }
    }

    @Transactional(value = Transactional.TxType.REQUIRED,rollbackOn = Exception.class)
    public void loginRecord(Account account){
        AccountLoginRecord accountLoginRecord=new AccountLoginRecord();
        accountLoginRecord.setAccount(account);
        accountLoginRecord.setLoginClient(LoginClient.H5);
        accountLoginRecord.setAuthMethod(AuthMethod.PASSWORD);
        accountLoginRecord.setClientIp(webInfo.getClientInfo().getIp());
        dao.save(accountLoginRecord);
    }
}
